﻿using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Collections.Extensions;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Extensions;
using Abp.Json;
using Abp.Linq.Extensions;
using Abp.Timing;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Mt.Site.Application.WorkFlows.Dto.Manager;
using Mt.Site.Core.Organizations.UserCache.Models;
using Mt.Site.Core.WorkFlows.Design;
using Mt.Site.Core.WorkFlows.Permissions;
using Mt.Site.Core.WorkFlows.Process;
using Mt.Site.Core.WorkFlows.Process.Entities;
using Mt.Site.Core.WorkFlows.Process.Models;
using Mt.Site.Core.WorkFlows.Process.Stores;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using System.Transactions;

namespace Mt.Site.Application.WorkFlows.Impl
{
    public class WorkFlowManagerAppService : ApplicationService, IWorkFlowManagerAppService
    {
        private readonly IWorkFlowSuperManager _workFlowSuperManager;
        private readonly IWorkFlowManager _workFlowManager;
        private readonly IRepository<WorkFlowPaper, Guid> _workFlowPaperRepository;
        private readonly IWorkFlowFactory _workFlowFactory;

        public WorkFlowManagerAppService(
            IWorkFlowSuperManager workFlowSuperManager, 
            IWorkFlowManager workFlowManager,
            IRepository<WorkFlowPaper, Guid> workFlowPaperRepository,
            IWorkFlowFactory workFlowFactory)
        {
            _workFlowSuperManager = workFlowSuperManager;
            _workFlowManager = workFlowManager;
            _workFlowPaperRepository = workFlowPaperRepository;
            _workFlowFactory = workFlowFactory;

        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow)]
        public async Task ResetRuntimeData()
        {
            var query = from p in _workFlowPaperRepository.GetAll()
                        select p.Id;
            var idList = await query.ToListAsync();

            foreach (var id in idList)
            {
                using (var uow = UnitOfWorkManager.Begin(new UnitOfWorkOptions
                {
                    Scope = TransactionScopeOption.RequiresNew
                }))
                {
                    await _workFlowSuperManager.ResetRuntimeDataAsync(id);
                    await uow.CompleteAsync();
                }
            }
        }

        //草稿箱删除
        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow)]
        public async Task DeleteAsync(List<Guid> idList)
        {
            await _workFlowSuperManager.DeleteAsync(idList);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task SuperDeleteAsync(List<Guid> idList)
        {
            await _workFlowSuperManager.SuperDeleteAsync(idList);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task CancelAsync(List<Guid> idList)
        {
            await _workFlowSuperManager.CancelAsync(idList);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task RestoreAsync(List<Guid> idList)
        {
            await _workFlowSuperManager.RestoreAsync(idList);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task ResumeExecuteAsync(PaperIdInput input)
        {
            await _workFlowSuperManager.ResumeExecuteAsync(input.PaperId);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task<SuperFormDataOutput> GetFormDataForEditAsync(PaperIdInput input)
        {
            await _workFlowManager.Initialize(input.PaperId);
            var paper = _workFlowManager.CurrentPaper.Paper;
            var workflow = _workFlowManager.WorkFlow;

            var remarkData = (await _workFlowManager.GetAllProcessDataWithArchiveAsync()).Select(c => c.CloneANewOne()).ToList();
            foreach (var item in remarkData)
            {
                item.NodeName = workflow.FindNode(item.NodeId).Definition.Name;
                item.UserInfo = item.UserInfoDtoJson.FromJsonString<UserInfoDto>();
                item.UserInfoDtoJson = "";
            }
            remarkData = remarkData.OrderBy(c => c.StepCode).ThenBy(c => c.Code).ThenBy(c => c.CreationTime)
                .ThenByDescending(c => c.UserInfo.Order).ToList();

            return new SuperFormDataOutput
            {
                Paper = ObjectMapper.Map<WorkFlowPaperDto>(paper),
                RemarkData = remarkData,
                LogData = await _workFlowManager.GetLogDataAsync(),
                FormData = await _workFlowSuperManager.GetFormDataForEditAsync(input.PaperId),
                FormHtml = workflow.Definition.FormHtml,
                Now = Clock.Now,
                IsHaveOnlineWord = workflow.Definition.IsHaveOnlineWord,
                CanEditAttachment = workflow.Definition.IsHaveAttachment,
                WfUniqueName = workflow.Definition.CustomData?.UniqueName,
                AdditionalMsg = await _workFlowManager.GetAllAdditionalMsg(),
                Relationships = await _workFlowManager.GetWorkFlowRelationshipsAsync()
            };
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task UpdateFormDataAsync(UpdateFormDataInput input)
        {
            await _workFlowSuperManager.UpdateFormDataAsync(input);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task RollBack(RollBackInput input)
        {
            await _workFlowSuperManager.RollBack(input.TaskId, input.PaperId);
        }

        [HttpPost]
        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin, WorkFlowPermissions.Pages_Manage_WorkFlow_Supervision, RequireAllPermissions = false)]
        public async Task<PagedResultDto<PagedManagerPaperDto>> GetPagedPapers(PagedMangerPaperInput input)
        {
            var query = _workFlowPaperRepository.GetAll()
                    .Where(t => t.PaperState == input.PaperState)
                    .WhereIf(!input.ExclusiveWorkFlowId.IsNullOrEmpty() && input.InclusiveWorkFlowId.IsNullOrEmpty(), t => !input.ExclusiveWorkFlowId.Contains(t.WorkFlowId))
                    .WhereIf(!input.InclusiveWorkFlowId.IsNullOrEmpty(), t => input.InclusiveWorkFlowId.Contains(t.WorkFlowId))
                    .WhereIf(input.StartDate != null, t => t.CreationTime >= input.StartDate.Value)
                    .WhereIf(input.EndDate != null, t => t.CreationTime <= input.EndDate.Value)
                    .WhereIf(input.UnitId > 0, t => t.UnitId == input.UnitId)
                    .WhereIf(!input.Filter.IsNullOrEmpty(), t => t.Title.Contains(input.Filter) || t.ReferNumber.Contains(input.Filter) || t.UserName == input.Filter);

            var count = await query.CountAsync();

            query = !string.IsNullOrWhiteSpace(input.Sorting)
                  ? query.OrderBy(input.Sorting).PageBy(input)
                  : query.OrderByDescending(t => t.CreationTime).PageBy(input);

            //Logger.Debug(query.ToSql());
            var list = await query.ToListAsync();

            List<PagedManagerPaperDto> result = new List<PagedManagerPaperDto>();
            foreach (var paper in list)
            {
                var item = new PagedManagerPaperDto
                {
                     PaperId = paper.Id,
                     Title = paper.Title,
                     CreationTime = paper.CreationTime,
                     WorkFlowId = paper.WorkFlowId,
                     NodeId = paper.NodeId,
                     UserId = paper.CreatorUserId ?? 0,
                     UserName = paper.UserName,
                     UnitId = paper.UnitId,
                     UnitName = paper.UnitName,
                     SerialNumber = paper.SerialNumber,
                     ReferNumber = paper.ReferNumber
                };
                var wf = await _workFlowFactory.GetWorkflowDefinitionAsync(item.WorkFlowId);
                item.WorkFlowName = wf.Definition.Name;
                item.NodeName = wf.FindNode(item.NodeId).Definition.Name;

                result.Add(item);
            }
            return new PagedResultDto<PagedManagerPaperDto>(count, result);
        }

        /// <inheritdoc/>
        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task UpdateReplyMsgAsync(UpdateReplyInput input)
        {
            await _workFlowSuperManager.UpdateReplyMsgAsync(input.TaskId, input.ReplyMsg);
        }

        /// <inheritdoc/>
        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task UpdateAdditionalMsgAsync(UpdateAdditionalMsgInput input)
        {
            await _workFlowSuperManager.UpdateAdditionalMsgAsync(input.MsgId, input.ReplyMsg);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task SetPaperUnMarked(EntityDto<Guid> input)
        {
            await _workFlowSuperManager.SetPaperUnMarked(input.Id);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task UpdateAudiTimeAsync(UpdateAuditTimeInput input)
        {
            await _workFlowSuperManager.UpdateAduditTimeAsync(input.StartTime, input.MarkTime, input.FinfishTime, input.Id);
        }

        [AbpAuthorize(WorkFlowPermissions.Pages_Manage_WorkFlow_Admin)]
        public async Task ArchiveAsync(PaperIdInput input)
        {
            await _workFlowSuperManager.ArchiveAsync(input.PaperId);
        }
    }
}
